
//-----------------MATRICES---------------
float4x4 xWorld: World;				
float4x4 xView: View;
float4x4 xProjection: Projection;
float4x4 xRotationMatrix;
float4x4 xReflectedView;
float4x4 xXRotMatrix;

//-----------------TEXTURES---------------

Texture xTexture;
sampler ColoredTextureSampler = sampler_state { texture = <xTexture> ;
    magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = mirror; AddressV = mirror;};

Texture xDirtTexture;
sampler DirtTextureSampler = sampler_state { texture = <xDirtTexture> ;
    magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = mirror; AddressV = mirror;};

Texture xGrassTexture;
sampler GrassTextureSampler = sampler_state { texture = <xGrassTexture> ;
    magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = mirror; AddressV = mirror;};

Texture xRockTexture;
sampler RockTextureSampler = sampler_state { texture = <xRockTexture> ;
    magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = mirror; AddressV = mirror;};

Texture xSnowTexture;
sampler SnowTextureSampler = sampler_state { texture = <xSnowTexture> ;
    magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = mirror; AddressV = mirror;};


Texture xRefractionMap;
sampler RefractionMapSampler = sampler_state { texture = <xRefractionMap> ;
    magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = mirror; AddressV = mirror;};

Texture xReflectionMap;
sampler ReflectionMapSampler = sampler_state { texture = <xReflectionMap> ;
    magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = mirror; AddressV = mirror;};

Texture xWaterBumpMap;
sampler WaterBumpMapSampler = sampler_state { texture = <xWaterBumpMap> ;
    magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = mirror; AddressV = mirror;};

Texture xRockBumpMap;
sampler RockBumpMapSampler = sampler_state { texture = <xRockBumpMap> ;
    magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = mirror; AddressV = mirror;};

textureCUBE xReflectionCube; 
samplerCUBE ReflectionCubeSampler = sampler_state
{
	Texture = <xReflectionCube>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    AddressU = wrap;
    AddressV = wrap;
};

//--------------- CONSTANTS ---------------

float xMaxHeight;
float xMinHeight;

bool xRefraction;
bool xReflection;

float xRockBumpHeight;


float4 xLightPosition;
float4 xAmbientLight;
float4 xCameraPosition;

float4 xWaterColor;
float xWaterLevel;


float xWindSpeed;
float xTime;


float xWaveLength;
float xWaveHeight;

//------------------- STRUCTS -------------------   


struct BufferToVertex
{
float3 Pos : POSITION;
float4 Normal : NORMAL;
float4 UV : TEXCOORD0;

};


struct VertexToPixel
{
float4 Pos:POSITION;
float4 Orig_Pos:TEXCOORD1;
float4 UV:TEXCOORD0;
float4 Normal: TEXCOORD2;
float4 TexWeights: TEXCOORD3;
float4 Pos3D:TEXCOORD4;
float4 Pos2D:TEXCOORD5;
};


struct PixelToFrame
{
float4 Color:COLOR;
float Depth:DEPTH;
};


struct WaterBufferToVertex
{
float3 Pos : POSITION;
float4 Normal : NORMAL;
float4 UV : TEXCOORD0;

};


struct WaterVertexToPixel
{
float4 Pos:POSITION;
float4 UV: TEXCOORD0;
float4 Normal: TEXCOORD2;
float4 ReflPos: TEXCOORD3;
float4 RefrPos: TEXCOORD4;
float4 Pos3D: TEXCOORD5;
float2 BumpPos: TEXCOORD6;
};

struct PointBufferToVertex
{
	float4 Pos : POSITION;
	float4 Diffuse : COLOR0;
};

struct PointVertexToPixel
{
	float4 Pos : POSITION;
	float4 Diffuse : COLOR;
	float Size : PSIZE;
};

struct PointPSInStruct
{	float4 Diffuse : COLOR;
	float4 Pos: POSITION;
	float4 Tex : TEXCOORD;
};








//---------------------- SHADERS ------------------------


// ---- PointSprite

void pointVS(PointBufferToVertex IN, out PointVertexToPixel OUT)
{
	float4x4 WorldViewProj;
	WorldViewProj=mul(xWorld,xView);
  	WorldViewProj=mul(WorldViewProj,xProjection);
        OUT.Pos = mul(IN.Pos, WorldViewProj);
	OUT.Diffuse = IN.Diffuse;
	OUT.Size = 150;
}

void pointPS(struct PointPSInStruct IN, out float4 OUT : COLOR)
{
	OUT = tex2D(SnowTextureSampler, IN.Tex) ;
}



// ---- MULTITEXTURED --------

VertexToPixel multitexturedVS(BufferToVertex IN)
{
  VertexToPixel OUT = (VertexToPixel)0;
  float4x4 WorldViewProj;
  WorldViewProj=mul(xWorld,xView);
  WorldViewProj=mul(WorldViewProj,xProjection);
  OUT.Pos=mul(float4(IN.Pos.xyz,1.0), WorldViewProj);
  OUT.Pos2D=OUT.Pos;
  OUT.Orig_Pos=float4(IN.Pos.xyz,1.0);
  OUT.Pos3D=mul(float4(IN.Pos.xyz,1.0),xWorld);
  OUT.UV=float4(IN.UV.xy,1.0,1.0);
  OUT.Normal=IN.Normal;
  float t=(IN.Pos.z-xMinHeight)/(xMaxHeight-xMinHeight);
  if (t<(1.0/7.0)) OUT.TexWeights=float4(1.0,0.0,0.0,0.0);
  if ((t>=(1.0/7.0)) && ((t<2.0/7.0))) OUT.TexWeights=float4(2.0-7.0*t,7.0*t-1,0.0,0.0);
  if ((t>=(2.0/7.0)) && ((t<3.0/7.0))) OUT.TexWeights=float4(0.0,1.0,0.0,0.0);
  if ((t>=(3.0/7.0)) && ((t<4.0/7.0))) OUT.TexWeights=float4(0.0,4.0-7.0*t,7.0*t-3,0.0);
  if ((t>=(4.0/7.0)) && ((t<5.0/7.0))) OUT.TexWeights=float4(0.0,0.0,1.0,0.0);
  if ((t>=(5.0/7.0)) && ((t<6.0/7.0))) OUT.TexWeights=float4(0.0,0.0,6.0-7.0*t,7.0*t-5.0);
  if (t>=(6.0/7.0)) OUT.TexWeights=float4(0.0,0.0,0.0,1.0);
  return OUT;
}

PixelToFrame multitexturedPS(VertexToPixel IN) 
{
PixelToFrame OUT=(PixelToFrame)0;
OUT.Depth=IN.Pos2D.z/IN.Pos2D.w;
float4 LightVector = normalize(xLightPosition-IN.Orig_Pos);
float4 Bump=tex2D(RockBumpMapSampler,IN.UV)*IN.TexWeights.z*xRockBumpHeight;
float LightIntensity = dot(LightVector, normalize(mul(IN.Normal+Bump,xRotationMatrix)));
if (xRefraction) if (IN.Pos3D.z>xWaterLevel) {OUT.Depth=1.0;LightIntensity=0.0f; xAmbientLight=float4(0,0,0,0);} 	
if (xReflection) if (IN.Pos3D.z<=xWaterLevel) {OUT.Depth=1.0;LightIntensity=0.0f; xAmbientLight=float4(0,0,0,0);}
OUT.Color = saturate((tex2D(DirtTextureSampler, IN.UV)*IN.TexWeights.x+
       		      tex2D(GrassTextureSampler, IN.UV)*IN.TexWeights.y+
                      tex2D(RockTextureSampler, IN.UV)*IN.TexWeights.z+
                      tex2D(SnowTextureSampler, IN.UV)*IN.TexWeights.w)*LightIntensity+xAmbientLight);
return OUT;       
}

//---------- TEXTURED ---------------

VertexToPixel texturedVS(BufferToVertex IN)
{
  VertexToPixel OUT = (VertexToPixel)0;
  float4x4 WorldViewProj;
  WorldViewProj=mul(xWorld,xView);
  WorldViewProj=mul(WorldViewProj,xProjection);
  OUT.Pos=mul(float4(IN.Pos.xyz,1.0), WorldViewProj);
  OUT.Pos2D=OUT.Pos;
  OUT.Pos3D=mul(float4(IN.Pos.xyz,1.0),xWorld);
  OUT.Orig_Pos=float4(IN.Pos.xyz,1.0);
  OUT.UV=float4(IN.UV.xy,1.0,1.0);
  OUT.Normal=IN.Normal;
	return OUT;
}

PixelToFrame texturedPS(VertexToPixel IN) 
{
PixelToFrame OUT = (PixelToFrame)0;
OUT.Depth=IN.Pos2D.z/IN.Pos2D.w;
float4 LightVector = normalize(xLightPosition - IN.Orig_Pos);
float LightIntensity = dot(LightVector,normalize(mul(IN.Normal,xRotationMatrix)));
if (xRefraction) if (IN.Pos3D.z>xWaterLevel) {OUT.Depth=1.0; LightIntensity=0.0f; xAmbientLight=float4(0,0,0,0);} 	
if (xReflection) if (IN.Pos3D.z<=xWaterLevel) {OUT.Depth=1.0; LightIntensity=0.0f; xAmbientLight=float4(0,0,0,0);} 	
OUT.Color = saturate(tex2D(ColoredTextureSampler, IN.UV)*LightIntensity+xAmbientLight);
return OUT;
}

//---------- TEXTURED with REFLECTIONS---------------

VertexToPixel texturedrefVS(BufferToVertex IN)
{
  VertexToPixel OUT = (VertexToPixel)0;
  float4x4 WorldViewProj;
  WorldViewProj=mul(xWorld,xView);
  WorldViewProj=mul(WorldViewProj,xProjection);
  OUT.Pos=mul(float4(IN.Pos.xyz,1.0), WorldViewProj);
  OUT.Pos2D=OUT.Pos;
  OUT.Pos3D=mul(float4(IN.Pos.xyz,1.0),xWorld);
  OUT.Orig_Pos=float4(IN.Pos.xyz,1.0);
  OUT.UV=float4(IN.UV.xy,1.0,1.0);
  OUT.Normal=IN.Normal;
	return OUT;
}

PixelToFrame texturedrefPS(VertexToPixel IN) 
{
PixelToFrame OUT = (PixelToFrame)0;
OUT.Depth=IN.Pos2D.z/IN.Pos2D.w;
float4 LightVector = normalize(xLightPosition - IN.Orig_Pos);
float4 Nm=normalize(mul(IN.Normal,xRotationMatrix));
float LightIntensity = saturate(dot(LightVector,Nm));

if (xRefraction) if (IN.Pos3D.z>xWaterLevel) {OUT.Depth=1.0; LightIntensity=0.0f; xAmbientLight=float4(0,0,0,0);} 	
if (xReflection) if (IN.Pos3D.z<=xWaterLevel) {OUT.Depth=1.0; LightIntensity=0.0f; xAmbientLight=float4(0,0,0,0);} 	
float4 EyeVec=mul(normalize(xCameraPosition-IN.Pos3D),xXRotMatrix);
float4 R=reflect(mul(Nm,xXRotMatrix),EyeVec);
float4 refcolor=texCUBE(ReflectionCubeSampler,R);
OUT.Color = saturate((tex2D(ColoredTextureSampler, IN.UV)+refcolor)*LightIntensity+xAmbientLight);
return OUT;
}

//----------- SOLID RED ----------
VertexToPixel solidredVS(BufferToVertex IN)
{
  VertexToPixel OUT = (VertexToPixel)0;
  float4x4 WorldViewProj;
  WorldViewProj=mul(xWorld,xView);
  WorldViewProj=mul(WorldViewProj,xProjection);
  OUT.Pos=mul(float4(IN.Pos.xyz,1.0), WorldViewProj);
  OUT.Pos2D=OUT.Pos;
  OUT.Pos3D=mul(float4(IN.Pos.xyz,1.0),xWorld);
  OUT.Orig_Pos=float4(IN.Pos.xyz,1.0);
  OUT.UV=float4(IN.UV.xy,1.0,1.0)+float4(0.03,0.03,0.0,0.0)*xWindSpeed*xTime;
  OUT.Normal=IN.Normal;
  return OUT;
}

PixelToFrame solidredPS(VertexToPixel IN) 
{
PixelToFrame OUT = (PixelToFrame)0;
OUT.Depth=IN.Pos2D.z/IN.Pos2D.w;
OUT.Color = float4(1.0,0,0,0); 	
return OUT;
}

//----------- SOLID GREEN ----------
VertexToPixel solidgreenVS(BufferToVertex IN)
{
  VertexToPixel OUT = (VertexToPixel)0;
  float4x4 WorldViewProj;
  WorldViewProj=mul(xWorld,xView);
  WorldViewProj=mul(WorldViewProj,xProjection);
  OUT.Pos=mul(float4(IN.Pos.xyz,1.0), WorldViewProj);
  OUT.Pos2D=OUT.Pos;
  OUT.Pos3D=mul(float4(IN.Pos.xyz,1.0),xWorld);
  OUT.Orig_Pos=float4(IN.Pos.xyz,1.0);
  OUT.UV=float4(IN.UV.xy,1.0,1.0)+float4(0.03,0.03,0.0,0.0)*xWindSpeed*xTime;
  OUT.Normal=IN.Normal;
  return OUT;
}

PixelToFrame solidgreenPS(VertexToPixel IN) 
{
PixelToFrame OUT = (PixelToFrame)0;
OUT.Depth=IN.Pos2D.z/IN.Pos2D.w;
OUT.Color = float4(0.0,1.0,0,0); 	
return OUT;
}
//----------- TEXTURED (NO LIGHTING) ----------
VertexToPixel nolighttexturedVS(BufferToVertex IN)
{
  VertexToPixel OUT = (VertexToPixel)0;
  float4x4 WorldViewProj;
  WorldViewProj=mul(xWorld,xView);
  WorldViewProj=mul(WorldViewProj,xProjection);
  OUT.Pos=mul(float4(IN.Pos.xyz,1.0), WorldViewProj);
  OUT.Pos2D=OUT.Pos;
  OUT.Pos3D=mul(float4(IN.Pos.xyz,1.0),xWorld);
  OUT.Orig_Pos=float4(IN.Pos.xyz,1.0);
  OUT.UV=float4(IN.UV.xy,1.0,1.0)+float4(0.03,0.03,0.0,0.0)*xWindSpeed*xTime;
  OUT.Normal=IN.Normal;
  return OUT;
}

PixelToFrame nolighttexturedPS(VertexToPixel IN) 
{
PixelToFrame OUT = (PixelToFrame)0;
OUT.Depth=IN.Pos2D.z/IN.Pos2D.w;
OUT.Color = saturate(tex2D(ColoredTextureSampler, IN.UV)+xAmbientLight);
if (xRefraction) if (IN.Pos3D.z>xWaterLevel) {OUT.Depth=1.0; OUT.Color=float4(0,0,0,0);} 	
if (xReflection) if (IN.Pos3D.z<=xWaterLevel) {OUT.Depth=1.0; OUT.Color=float4(0,0,0,0);} 	
return OUT;
}



//---------------- WATER ---------------
WaterVertexToPixel waterVS(WaterBufferToVertex IN)
{
  WaterVertexToPixel OUT = (WaterVertexToPixel)0;
  float4x4 WorldViewProj, RefWorldViewProj;
	  float3 WaveVector = float3(0,0,1.2*sin(0.5*IN.Pos.x+xTime)+1.15*sin(0.6*IN.Pos.y+0.9f*xTime));
  
  WorldViewProj=mul(xWorld,xView);
  WorldViewProj=mul(WorldViewProj,xProjection);
  
  RefWorldViewProj = mul (xWorld,xReflectedView);
  RefWorldViewProj = mul (RefWorldViewProj,xProjection);
  
  OUT.Pos=mul(float4(IN.Pos.xyz+WaveVector,1.0), WorldViewProj);
  OUT.RefrPos=mul(float4(IN.Pos.xyz+WaveVector,1.0),WorldViewProj);
  OUT.ReflPos=mul(float4(IN.Pos.xyz+WaveVector,1.0),RefWorldViewProj);
  OUT.Pos3D=float4(IN.Pos.xyz+WaveVector,1.0);
  
  OUT.UV=float4(IN.UV.xy,1.0,1.0);
  OUT.Normal=IN.Normal;
  OUT.BumpPos=IN.UV/xWaveLength+xTime*xWindSpeed*float2(0.0,1.0);
  return OUT;
}


float4 waterPS(WaterVertexToPixel IN) : COLOR 
{
    float4 ReflColor,RefrColor;
    float2 ProjectedTexCoords;
    float4 BumpColor = tex2D(WaterBumpMapSampler, IN.BumpPos);
    float2 Perturbation = xWaveHeight*(BumpColor.rg-0.5f);
    
    ProjectedTexCoords.x = IN.ReflPos.x/IN.ReflPos.w/2.0f + 0.5f;
    ProjectedTexCoords.y = -IN.ReflPos.y/IN.ReflPos.w/2.0f + 0.5f;
    ReflColor=tex2D(ReflectionMapSampler, ProjectedTexCoords+Perturbation);
    
    ProjectedTexCoords.x = IN.RefrPos.x/IN.RefrPos.w/2.0f + 0.5f;
    ProjectedTexCoords.y = -IN.RefrPos.y/IN.RefrPos.w/2.0f + 0.5f;
    RefrColor=tex2D(RefractionMapSampler, ProjectedTexCoords+Perturbation);
    
    float3 EyeVec=normalize(xCameraPosition.xyz-IN.Pos3D);
    float FresnelTerm = dot(EyeVec, normalize(IN.Normal));
    
    //FresnelTerm=0;
    return saturate(FresnelTerm*RefrColor+(1-FresnelTerm)*ReflColor+xWaterColor);

}


// ------------ TECHNIQUES --------------

technique nolighttextured {
	pass p0 {
		VertexShader = compile vs_3_0 nolighttexturedVS();
		PixelShader = compile ps_3_0 nolighttexturedPS();
	}
}

technique textured {
	pass p0 {
		VertexShader = compile vs_3_0 texturedVS();
		PixelShader = compile ps_3_0 texturedPS();
	}
}

technique texturedref {
	pass p0 {
		VertexShader = compile vs_3_0 texturedrefVS();
		PixelShader = compile ps_3_0 texturedrefPS();
	}
}

technique multitextured {
	pass p0 {
		VertexShader = compile vs_3_0 multitexturedVS();
		PixelShader = compile ps_3_0 multitexturedPS();
	}
}

technique water {
	pass p0 {
		VertexShader = compile vs_3_0 waterVS();
		PixelShader = compile ps_3_0 waterPS();
	}
}


technique solidred {
	pass p0 {
		VertexShader = compile vs_3_0 solidredVS();
		PixelShader = compile ps_3_0 solidredPS();
	}
}

technique solidgreen {
	pass p0 {
		VertexShader = compile vs_3_0 solidgreenVS();
		PixelShader = compile ps_3_0 solidgreenPS();
	}
}


technique point
{
	pass
	{
		Texture[0] = (xSnowTexture);
		ColorOp[0] = SELECTARG1;
		ColorArg1[0] = TEXTURE;
		AlphaOp[0] = MODULATE;
		AlphaArg1[0] = TEXTURE;
		AlphaArg2[0] = DIFFUSE;
		ColorOp[1] = DISABLE;
		AlphaOp[1] = DISABLE;

		PointSpriteEnable = true;

		Lighting = false;
		ZEnable = true;
		CullMode = NONE;
		AlphaBlendEnable = true;

		BlendOp = ADD;
		SrcBlend = SRCALPHA;
		DestBlend = ONE;
		ZWriteEnable = false;
		VertexShader = compile vs_1_1 pointVS();
		PixelShader = compile ps_1_1 pointPS();
	}
}